{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "import tensorflow as tf\n",
    "import glob\n",
    "import os\n",
    "import random "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'2.2.0'"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "tf.__version__"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "gpus = tf.config.experimental.list_physical_devices( device_type = 'GPU' )\n",
    "# 设置该程序可见的GPU：写到最前面！\n",
    "tf.config.experimental.set_visible_devices( devices = gpus[0:3], device_type = 'GPU' )"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 一、数据导入与标签制作："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 原始训练数据 + 验证数据：路径全是/，没有//\n",
    "all_path = glob.glob('../train_new2/*')\n",
    "all_total = len(all_path)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "6480"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "all_total"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 随机打散：\n",
    "random.shuffle( all_path )  # 无返回值，直接在原变量上做改变"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['../train_new2/2_1_16_1.jpg',\n",
       " '../train_new2/3_2_25_5.jpg',\n",
       " '../train_new2/2_3_01_3.jpg',\n",
       " '../train_new2/3_1_29_1_1_1_1.jpg',\n",
       " '../train_new2/4_3_20_1_1_1.jpg',\n",
       " '../train_new2/5_3_17_3.jpg',\n",
       " '../train_new2/5_2_10_1_1_1_1.jpg',\n",
       " '../train_new2/3_3_54_1_1_1.jpg',\n",
       " '../train_new2/6_2_49_2.jpg',\n",
       " '../train_new2/2_1_04_1.jpg']"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "all_path[0:10]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 提取标签：1:1 \n",
    "all_label = [] \n",
    "for x in range( all_total ):\n",
    "    label = int( all_path[x].split('/')[-1].split('.')[0].split('_')[-1] )\n",
    "    if label == 1:\n",
    "        all_label.append(1)  # 真人\n",
    "    else:\n",
    "        all_label.append(0)  # 图片"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(list, 6480)"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "type(all_label), len(all_label)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 二、制作数据集与划分："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "all_dataset = tf.data.Dataset.from_tensor_slices( (all_path, all_label) )  # path + label"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<TensorSliceDataset shapes: ((), ()), types: (tf.string, tf.int32)>"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "all_dataset"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(5184, 1296)"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 划分训练和验证：8:2\n",
    "val_count = int( all_total*0.2 )\n",
    "train_count = all_total - val_count\n",
    "train_count, val_count"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "# skip函数略过多少，take函数取多少：\n",
    "train_dataset_org = all_dataset.skip( val_count )  # 略过xx个，剩下全要\n",
    "val_dataset_org = all_dataset.take( val_count )   # 取xx个，剩下全不要"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(<SkipDataset shapes: ((), ()), types: (tf.string, tf.int32)>,\n",
       " <TakeDataset shapes: ((), ()), types: (tf.string, tf.int32)>)"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "train_dataset_org, val_dataset_org"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 三、网络自定义："
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "分两部分自定义：\n",
    "- 定义预处理函数；\n",
    "- 定义网络结构。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 对训练数据及标签的预处理：先等比缩放，再裁剪\n",
    "# 原始都是1080 x 1920 —— 先缩放到600 x 600 —— 再随机裁剪到512 x 512 —— 注：512x512情况下计算太慢了！\n",
    "def preprocessing_train(path, label):\n",
    "    # 数据读入：image\n",
    "    image = tf.io.read_file( path )                       # 文件读取\n",
    "    image = tf.image.decode_jpeg( image, channels = 3 )   # 文件解码成jpg图片，并给定图片的通道数（默认为0！）\n",
    "    # 数据增强：resize + crop\n",
    "    image = tf.image.resize( image, [300,300], method = tf.image.ResizeMethod.NEAREST_NEIGHBOR ) # 等比例缩放：不用写通道数\n",
    "    image = tf.image.random_crop( image, size = [256,256,3] )  # 随机裁剪：裁剪时要写最后一维的通道数\n",
    "    image = tf.image.random_flip_left_right( image )  # 随机左右翻转\n",
    "    image = tf.image.random_flip_up_down( image )     # 随机上下翻转\n",
    "    image = tf.cast( image, tf.float32 )              # 转换数据类型：读入默认是int8\n",
    "    image = image / 255                               # 归一化\n",
    "    # 标签：label\n",
    "    label = tf.reshape( label, [1] )\n",
    "    # 返回结果：\n",
    "    return image, label"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 对训练数据及标签的预处理：只等比缩放到同样的尺寸\n",
    "def preprocessing_val(path, label):\n",
    "    # 数据读入：image\n",
    "    image = tf.io.read_file( path )                       # 文件读取\n",
    "    image = tf.image.decode_jpeg( image, channels = 3 )   # 文件解码成jpg图片，并给定图片的通道数（默认为0！）\n",
    "    # 等比缩放：resize\n",
    "    image = tf.image.resize( image, [256,256] )           # 等比缩放，不要选裁剪！\n",
    "    image = tf.cast( image, tf.float32 )                  # 转换数据类型：读入默认是int8\n",
    "    image = image / 255                                   # 归一化\n",
    "    # 标签：label\n",
    "    label = tf.reshape( label, [1] )\n",
    "    # 返回结果：\n",
    "    return image, label"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 测试数据预处理：\n",
    "def preprocessing_test(path, label):\n",
    "    # 数据读入：image\n",
    "    image = tf.io.read_file( path )                       # 文件读取\n",
    "    image = tf.image.decode_jpeg( image, channels = 3 )   # 文件解码成jpg图片，并给定图片的通道数（默认为0！）\n",
    "    # 等比缩放：resize\n",
    "    image = tf.image.resize( image, [256,256] )           # 等比缩放，不要选裁剪！\n",
    "    image = tf.cast( image, tf.float32 )                  # 转换数据类型：读入默认是int8\n",
    "    image = image / 255                                   # 归一化\n",
    "    # 标签：label\n",
    "    label = tf.reshape( label, [1] )\n",
    "    # 返回结果：\n",
    "    return image, label"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 用tf.data创建输入数据集：\n",
    "AUTOTUNE = tf.data.experimental.AUTOTUNE   # 新操作：在tf.data模块使用时，会自动根据cpu来情况进行并行计算处理！\n",
    "# 训练数据：\n",
    "train_dataset = train_dataset_org.map( preprocessing_train, num_parallel_calls = AUTOTUNE )  # 这里用到上面预处理的函数\n",
    "# 测试数据：\n",
    "val_dataset = val_dataset_org.map( preprocessing_val, num_parallel_calls = AUTOTUNE )      # 这里用到上面预处理的函数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(<ParallelMapDataset shapes: ((256, 256, 3), (1,)), types: (tf.float32, tf.int32)>,\n",
       " <ParallelMapDataset shapes: ((256, 256, 3), (1,)), types: (tf.float32, tf.int32)>)"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "train_dataset, val_dataset"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**网络搭建：数据又一次打散**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 乱序、批划分：\n",
    "BATCH_SIZE = 16\n",
    "# 训练数据：\n",
    "train_dataset = train_dataset.shuffle(train_count).batch(BATCH_SIZE)  # 乱序 + 划分批次 \n",
    "train_dataset = train_dataset.prefetch(AUTOTUNE)  # 新操作：预取到缓存：加速处理\n",
    "# 验证数据：\n",
    "val_dataset = val_dataset.batch(BATCH_SIZE)  # 乱序 + 划分批次 \n",
    "val_dataset = val_dataset.prefetch(AUTOTUNE)  # 新操作：预取到缓存：加速处理"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 图像不断缩小，相当于卷积核视野不断变大！\n",
    "# 1. 加批标准化层：加到每个卷积层、全连接层的后面\n",
    "model = tf.keras.Sequential([\n",
    "    tf.keras.layers.Conv2D(64, (3, 3), input_shape=(256, 256, 3), activation='relu'),\n",
    "    tf.keras.layers.BatchNormalization(),\n",
    "    tf.keras.layers.Conv2D(64, (3, 3), activation='relu'),\n",
    "    tf.keras.layers.BatchNormalization(),\n",
    "    tf.keras.layers.MaxPooling2D(),\n",
    "    \n",
    "    tf.keras.layers.Conv2D(128, (3, 3), activation='relu'),\n",
    "    tf.keras.layers.BatchNormalization(),\n",
    "    tf.keras.layers.Conv2D(128, (3, 3), activation='relu'),\n",
    "    tf.keras.layers.BatchNormalization(),\n",
    "    tf.keras.layers.MaxPooling2D(),\n",
    "    \n",
    "    tf.keras.layers.Conv2D(256, (3, 3), activation='relu'),\n",
    "    tf.keras.layers.BatchNormalization(),\n",
    "    tf.keras.layers.Conv2D(256, (3, 3), activation='relu'),\n",
    "    tf.keras.layers.BatchNormalization(),\n",
    "    tf.keras.layers.MaxPooling2D(),\n",
    "    \n",
    "    tf.keras.layers.Conv2D(512, (3, 3), activation='relu'),\n",
    "    tf.keras.layers.BatchNormalization(),\n",
    "    tf.keras.layers.Conv2D(512, (3, 3), activation='relu'),\n",
    "    tf.keras.layers.BatchNormalization(),  # 后面用AveragePooling了，不需要这里的Maxpooling\n",
    "    \n",
    "    # 过渡：进入全连接层\n",
    "    tf.keras.layers.GlobalAveragePooling2D(),\n",
    "    \n",
    "    tf.keras.layers.Dense(256, activation='relu'),\n",
    "    tf.keras.layers.BatchNormalization(),\n",
    "    \n",
    "    tf.keras.layers.Dense(128, activation='relu'),\n",
    "    tf.keras.layers.BatchNormalization(),\n",
    "\n",
    "    tf.keras.layers.Dense(64, activation='relu'),\n",
    "    tf.keras.layers.BatchNormalization(),\n",
    " \n",
    "    tf.keras.layers.Dense(1, activation = 'sigmoid')\n",
    "])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Model: \"sequential_3\"\n",
      "_________________________________________________________________\n",
      "Layer (type)                 Output Shape              Param #   \n",
      "=================================================================\n",
      "conv2d_24 (Conv2D)           (None, 254, 254, 64)      1792      \n",
      "_________________________________________________________________\n",
      "batch_normalization_36 (Batc (None, 254, 254, 64)      256       \n",
      "_________________________________________________________________\n",
      "conv2d_25 (Conv2D)           (None, 252, 252, 64)      36928     \n",
      "_________________________________________________________________\n",
      "batch_normalization_37 (Batc (None, 252, 252, 64)      256       \n",
      "_________________________________________________________________\n",
      "max_pooling2d_9 (MaxPooling2 (None, 126, 126, 64)      0         \n",
      "_________________________________________________________________\n",
      "conv2d_26 (Conv2D)           (None, 124, 124, 128)     73856     \n",
      "_________________________________________________________________\n",
      "batch_normalization_38 (Batc (None, 124, 124, 128)     512       \n",
      "_________________________________________________________________\n",
      "conv2d_27 (Conv2D)           (None, 122, 122, 128)     147584    \n",
      "_________________________________________________________________\n",
      "batch_normalization_39 (Batc (None, 122, 122, 128)     512       \n",
      "_________________________________________________________________\n",
      "max_pooling2d_10 (MaxPooling (None, 61, 61, 128)       0         \n",
      "_________________________________________________________________\n",
      "conv2d_28 (Conv2D)           (None, 59, 59, 256)       295168    \n",
      "_________________________________________________________________\n",
      "batch_normalization_40 (Batc (None, 59, 59, 256)       1024      \n",
      "_________________________________________________________________\n",
      "conv2d_29 (Conv2D)           (None, 57, 57, 256)       590080    \n",
      "_________________________________________________________________\n",
      "batch_normalization_41 (Batc (None, 57, 57, 256)       1024      \n",
      "_________________________________________________________________\n",
      "max_pooling2d_11 (MaxPooling (None, 28, 28, 256)       0         \n",
      "_________________________________________________________________\n",
      "conv2d_30 (Conv2D)           (None, 26, 26, 512)       1180160   \n",
      "_________________________________________________________________\n",
      "batch_normalization_42 (Batc (None, 26, 26, 512)       2048      \n",
      "_________________________________________________________________\n",
      "conv2d_31 (Conv2D)           (None, 24, 24, 512)       2359808   \n",
      "_________________________________________________________________\n",
      "batch_normalization_43 (Batc (None, 24, 24, 512)       2048      \n",
      "_________________________________________________________________\n",
      "global_average_pooling2d_3 ( (None, 512)               0         \n",
      "_________________________________________________________________\n",
      "dense_15 (Dense)             (None, 256)               131328    \n",
      "_________________________________________________________________\n",
      "batch_normalization_44 (Batc (None, 256)               1024      \n",
      "_________________________________________________________________\n",
      "dense_16 (Dense)             (None, 128)               32896     \n",
      "_________________________________________________________________\n",
      "batch_normalization_45 (Batc (None, 128)               512       \n",
      "_________________________________________________________________\n",
      "dense_17 (Dense)             (None, 64)                8256      \n",
      "_________________________________________________________________\n",
      "batch_normalization_46 (Batc (None, 64)                256       \n",
      "_________________________________________________________________\n",
      "dense_18 (Dense)             (None, 1)                 65        \n",
      "=================================================================\n",
      "Total params: 4,867,393\n",
      "Trainable params: 4,862,657\n",
      "Non-trainable params: 4,736\n",
      "_________________________________________________________________\n"
     ]
    }
   ],
   "source": [
    "model.summary()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 模型编译：\n",
    "model.compile(optimizer = 'adam',\n",
    "              loss = 'binary_crossentropy',\n",
    "              metrics = ['acc']\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 定义保存模型的回调函数：保存整个模型、只保存最好的！\n",
    "# 设置保存的路径：\n",
    "checkpoint_path = '/home/gaoboyu/活体检测项目/model_large/'\n",
    "# 设置回调函数保存模型：没设置的参数都默认\n",
    "cp_callback_model = tf.keras.callbacks.ModelCheckpoint(\n",
    "    filepath = checkpoint_path,\n",
    "    monitor = 'val_acc',\n",
    "    save_best_only = True  # 监控的目标：如果新的epoch结果比前一个要好，那就重新保存最新的，删掉旧的！\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {
    "collapsed": true,
    "jupyter": {
     "outputs_hidden": true
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1/100\n",
      "324/324 [==============================] - ETA: 0s - loss: 0.5753 - acc: 0.7176INFO:tensorflow:Assets written to: /home/gaoboyu/活体检测项目/model_large/assets\n",
      "324/324 [==============================] - 153s 472ms/step - loss: 0.5753 - acc: 0.7176 - val_loss: 0.9586 - val_acc: 0.6042\n",
      "Epoch 2/100\n",
      " 79/324 [======>.......................] - ETA: 1:43 - loss: 0.5066 - acc: 0.7508"
     ]
    },
    {
     "ename": "KeyboardInterrupt",
     "evalue": "",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mKeyboardInterrupt\u001b[0m                         Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-40-00d51a647ce8>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m      8\u001b[0m     \u001b[0mvalidation_steps\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mval_count\u001b[0m \u001b[0;34m//\u001b[0m \u001b[0mBATCH_SIZE\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      9\u001b[0m     \u001b[0;31m# 回调函数：\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 10\u001b[0;31m     \u001b[0mcallbacks\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0mcp_callback_model\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     11\u001b[0m )\n",
      "\u001b[0;32m/usr/local/Anaconda33/lib/python3.7/site-packages/tensorflow/python/keras/engine/training.py\u001b[0m in \u001b[0;36m_method_wrapper\u001b[0;34m(self, *args, **kwargs)\u001b[0m\n\u001b[1;32m     64\u001b[0m   \u001b[0;32mdef\u001b[0m \u001b[0m_method_wrapper\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     65\u001b[0m     \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_in_multi_worker_mode\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m  \u001b[0;31m# pylint: disable=protected-access\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 66\u001b[0;31m       \u001b[0;32mreturn\u001b[0m \u001b[0mmethod\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     67\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     68\u001b[0m     \u001b[0;31m# Running inside `run_distribute_coordinator` already.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m/usr/local/Anaconda33/lib/python3.7/site-packages/tensorflow/python/keras/engine/training.py\u001b[0m in \u001b[0;36mfit\u001b[0;34m(self, x, y, batch_size, epochs, verbose, callbacks, validation_split, validation_data, shuffle, class_weight, sample_weight, initial_epoch, steps_per_epoch, validation_steps, validation_batch_size, validation_freq, max_queue_size, workers, use_multiprocessing)\u001b[0m\n\u001b[1;32m    853\u001b[0m                 \u001b[0mcontext\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0masync_wait\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    854\u001b[0m               \u001b[0mlogs\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mtmp_logs\u001b[0m  \u001b[0;31m# No error, now safe to assign to logs.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 855\u001b[0;31m               \u001b[0mcallbacks\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mon_train_batch_end\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mstep\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlogs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    856\u001b[0m         \u001b[0mepoch_logs\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcopy\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcopy\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mlogs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    857\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m/usr/local/Anaconda33/lib/python3.7/site-packages/tensorflow/python/keras/callbacks.py\u001b[0m in \u001b[0;36mon_train_batch_end\u001b[0;34m(self, batch, logs)\u001b[0m\n\u001b[1;32m    387\u001b[0m     \"\"\"\n\u001b[1;32m    388\u001b[0m     \u001b[0;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_should_call_train_batch_hooks\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 389\u001b[0;31m       \u001b[0mlogs\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_process_logs\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mlogs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    390\u001b[0m       \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_call_batch_hook\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mModeKeys\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mTRAIN\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'end'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mbatch\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlogs\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mlogs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    391\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m/usr/local/Anaconda33/lib/python3.7/site-packages/tensorflow/python/keras/callbacks.py\u001b[0m in \u001b[0;36m_process_logs\u001b[0;34m(self, logs)\u001b[0m\n\u001b[1;32m    263\u001b[0m     \u001b[0;34m\"\"\"Turns tensors into numpy arrays or Python scalars.\"\"\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    264\u001b[0m     \u001b[0;32mif\u001b[0m \u001b[0mlogs\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 265\u001b[0;31m       \u001b[0;32mreturn\u001b[0m \u001b[0mtf_utils\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mto_numpy_or_python_type\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mlogs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    266\u001b[0m     \u001b[0;32mreturn\u001b[0m \u001b[0;34m{\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    267\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m/usr/local/Anaconda33/lib/python3.7/site-packages/tensorflow/python/keras/utils/tf_utils.py\u001b[0m in \u001b[0;36mto_numpy_or_python_type\u001b[0;34m(tensors)\u001b[0m\n\u001b[1;32m    521\u001b[0m     \u001b[0;32mreturn\u001b[0m \u001b[0mt\u001b[0m  \u001b[0;31m# Don't turn ragged or sparse tensors to NumPy.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    522\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 523\u001b[0;31m   \u001b[0;32mreturn\u001b[0m \u001b[0mnest\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmap_structure\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0m_to_single_numpy_or_python_type\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtensors\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    524\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m/usr/local/Anaconda33/lib/python3.7/site-packages/tensorflow/python/util/nest.py\u001b[0m in \u001b[0;36mmap_structure\u001b[0;34m(func, *structure, **kwargs)\u001b[0m\n\u001b[1;32m    615\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    616\u001b[0m   return pack_sequence_as(\n\u001b[0;32m--> 617\u001b[0;31m       \u001b[0mstructure\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0mfunc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mx\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mentries\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    618\u001b[0m       expand_composites=expand_composites)\n\u001b[1;32m    619\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m/usr/local/Anaconda33/lib/python3.7/site-packages/tensorflow/python/util/nest.py\u001b[0m in \u001b[0;36m<listcomp>\u001b[0;34m(.0)\u001b[0m\n\u001b[1;32m    615\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    616\u001b[0m   return pack_sequence_as(\n\u001b[0;32m--> 617\u001b[0;31m       \u001b[0mstructure\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0mfunc\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mx\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mentries\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    618\u001b[0m       expand_composites=expand_composites)\n\u001b[1;32m    619\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m/usr/local/Anaconda33/lib/python3.7/site-packages/tensorflow/python/keras/utils/tf_utils.py\u001b[0m in \u001b[0;36m_to_single_numpy_or_python_type\u001b[0;34m(t)\u001b[0m\n\u001b[1;32m    517\u001b[0m   \u001b[0;32mdef\u001b[0m \u001b[0m_to_single_numpy_or_python_type\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mt\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    518\u001b[0m     \u001b[0;32mif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mt\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mops\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mTensor\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 519\u001b[0;31m       \u001b[0mx\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mt\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mnumpy\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    520\u001b[0m       \u001b[0;32mreturn\u001b[0m \u001b[0mx\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mitem\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mndim\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;36m0\u001b[0m \u001b[0;32melse\u001b[0m \u001b[0mx\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    521\u001b[0m     \u001b[0;32mreturn\u001b[0m \u001b[0mt\u001b[0m  \u001b[0;31m# Don't turn ragged or sparse tensors to NumPy.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m/usr/local/Anaconda33/lib/python3.7/site-packages/tensorflow/python/framework/ops.py\u001b[0m in \u001b[0;36mnumpy\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m    959\u001b[0m     \"\"\"\n\u001b[1;32m    960\u001b[0m     \u001b[0;31m# TODO(slebedev): Consider avoiding a copy for non-CPU or remote tensors.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 961\u001b[0;31m     \u001b[0mmaybe_arr\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_numpy\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m  \u001b[0;31m# pylint: disable=protected-access\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    962\u001b[0m     \u001b[0;32mreturn\u001b[0m \u001b[0mmaybe_arr\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcopy\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmaybe_arr\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mndarray\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32melse\u001b[0m \u001b[0mmaybe_arr\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    963\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m/usr/local/Anaconda33/lib/python3.7/site-packages/tensorflow/python/framework/ops.py\u001b[0m in \u001b[0;36m_numpy\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m    925\u001b[0m     \u001b[0;31m# pylint: disable=protected-access\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    926\u001b[0m     \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 927\u001b[0;31m       \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_numpy_internal\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    928\u001b[0m     \u001b[0;32mexcept\u001b[0m \u001b[0mcore\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_NotOkStatusException\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0me\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    929\u001b[0m       \u001b[0msix\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mraise_from\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcore\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_status_to_exception\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0me\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcode\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0me\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmessage\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mKeyboardInterrupt\u001b[0m: "
     ]
    }
   ],
   "source": [
    "# 模型训练\n",
    "EPOCHES = 100\n",
    "history = model.fit(\n",
    "    train_dataset,\n",
    "    epochs = EPOCHES,\n",
    "    steps_per_epoch = train_count // BATCH_SIZE,\n",
    "    validation_data = val_dataset,\n",
    "    validation_steps = val_count // BATCH_SIZE,\n",
    "    # 回调函数：\n",
    "    callbacks = [cp_callback_model]\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# history文件保存：\n",
    "import pickle\n",
    "history_path = '/home/gaoboyu/活体检测项目/history/history1.text'\n",
    "with open(history_path, 'wb') as file_pi:\n",
    "    pickle.dump(history.history, file_pi)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 格式转存：\n",
    "model_new = tf.keras.models.load_model( '../model_large/' )\n",
    "model_new.save( '/home/gaoboyu/活体检测项目/model_h5/model_large.h5' )"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 四、测试数据："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "180/180 [==============================] - 23s 125ms/step - loss: 0.0063 - acc: 0.9976\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "[0.00627910764887929, 0.9975694417953491]"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 模型导入：\n",
    "model_new = tf.keras.models.load_model( '../model_h5/model_large.h5' )\n",
    "\n",
    "# 导入测试数据：\n",
    "test_path = glob.glob('../test_new1/*')\n",
    "# 随机打散：\n",
    "random.shuffle( test_path )  # 无返回值，直接在原变量上做改变\n",
    "# 提取标签：\n",
    "test_label = [] \n",
    "for x in range( len(test_path) ):\n",
    "    label = int( test_path[x].split('/')[-1].split('.')[0].split('_')[-1] )\n",
    "    if label == 1:\n",
    "        test_label.append(1)  # 真人\n",
    "    else:\n",
    "        test_label.append(0)  # 图片\n",
    "        \n",
    "# 创建数据集：\n",
    "test_dataset = tf.data.Dataset.from_tensor_slices( (test_path, test_label) )  # path + label\n",
    "# 加batch维度：\n",
    "AUTOTUNE = tf.data.experimental.AUTOTUNE   # 新操作：在tf.data模块使用时，会自动根据cpu来情况进行并行计算处理！\n",
    "BATCH_SIZE = 16\n",
    "test_dataset = test_dataset.map( preprocessing_test, num_parallel_calls = AUTOTUNE )\n",
    "test_dataset = test_dataset.cache().batch(BATCH_SIZE)\n",
    "test_dataset\n",
    "\n",
    "# 测试：\n",
    "model_new.evaluate(test_dataset)\n",
    "\n",
    "# # 模型重保存为.h5格式：\n",
    "# model_new.save( '/home/gaoboyu/活体检测项目/model_h5/model_large.h5' )\n",
    "\n",
    "# # 再次导入.h5格式模型 + 评估：\n",
    "# model_newh5 = tf.keras.models.load_model( '/home/gaoboyu/活体检测项目/model/model1.h5' )\n",
    "# model_newh5.evaluate( test_dataset )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
